package com.abso.mp3tunes.locker.ui.jobs;

import java.util.Map;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;

import com.abso.mp3tunes.locker.core.LockerServiceException;
import com.abso.mp3tunes.locker.ui.viewers.PendingNode;

/**
 * An abstract base class for jobs able to retrieve tree child nodes in
 * background.
 */
public abstract class GetTreeChildNodesJob extends Job {

	/** The parent element. */
	private Object parent;

	/** The parent-child map to be filled by this job. */
	private Map parentChildMap;

	/** The tree viewer being updated. */
	private TreeViewer viewer;

	/**
	 * Constructs a new job.
	 * 
	 * @param jobName
	 *            the name of the job.
	 * @param parent
	 *            the parent element.
	 * @param parentChildMap
	 *            the parent-child map to be filled by this job.
	 * @param viewer
	 *            the tree viewer being updated.
	 */
	public GetTreeChildNodesJob(String jobName, Object parent,
			Map parentChildMap, TreeViewer viewer) {
		super(jobName);
		this.parent = parent;
		this.parentChildMap = parentChildMap;
		this.viewer = viewer;
		Object[] tempChildren = new Object[] { new PendingNode() };
		parentChildMap.put(parent, tempChildren);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
	 */
	protected IStatus run(IProgressMonitor monitor) {
		Object[] children = null;
		try {
			children = doGetChildren();
		} catch (LockerServiceException e) {
			children = new Object[] { e };
		}
		parentChildMap.put(parent, children);
		refreshInUIThread(parent);
		return Status.OK_STATUS;
	}

	/**
	 * Returns the parent element.
	 * 
	 * @return the parent element.
	 */
	protected Object getParent() {
		return parent;
	}

	/**
	 * Computes and returns the child nodes.
	 * 
	 * @return the child nodes.
	 * @throws LockerServiceException
	 *             if an error occurred computing the child nodes.
	 */
	protected abstract Object[] doGetChildren() throws LockerServiceException;

	/**
	 * Refreshes the specified element in the tree viewer.
	 * 
	 * @param element
	 *            the node being refreshed.
	 */
	private void refreshInUIThread(final Object element) {
		Control control = viewer.getControl();
		if ((control != null) && !control.isDisposed()) {
			Display display = control.getDisplay();
			if (display != null) {
				display.asyncExec(new Runnable() {
					public void run() {
						viewer.refresh(element);
					}
				});
			}
		}
	}

}
